from manim import *
from numpy import pi

class FibonacciAnimation(Scene):
    def construct(self):
        # 定义斐波那契数列的项数
        n = 8  # 只需要两个正方形来画第一条弧线
        # 初始化斐波那契数列
        fib = [1, 1]
        for i in range(2, n):
            fib.append(fib[i - 1] + fib[i - 2])

        # 创建正方形列表
        squares = []
        # 创建标签列表
        labels = []
        # 初始位置
        start_pos = [-2, 1, 0]
        direction = RIGHT

        # 定义缩放因子，可根据需要调整
        scale_factor = 0.3

        # 定义颜色列表
        colors = [BLUE, GREEN, YELLOW, ORANGE, RED, PURPLE, PINK, TEAL]

        # 创建显示整个数列值的文本对象
        fib_text = Text(f"斐波那契数列: {fib[:1]}").scale(0.5).to_edge(UP)
        self.add(fib_text)

        for i in range(n):
            # 创建正方形，使用缩放因子调整边长，并设置颜色
            square = Square(side_length=fib[i] * scale_factor)
            square.set_fill(colors[i % len(colors)], opacity=0.7)  # 设置填充颜色和不透明度
            if i == 0:
                square.move_to(start_pos)
            else:
                prev_square = squares[i - 1]
                if np.allclose(direction, RIGHT):
                    square.next_to(prev_square, UP, buff=0, aligned_edge=RIGHT)
                elif np.allclose(direction, UP):
                    square.next_to(prev_square, LEFT, buff=0, aligned_edge=UP)
                elif np.allclose(direction, LEFT):
                    square.next_to(prev_square, DOWN, buff=0, aligned_edge=LEFT)
                else:
                    square.next_to(prev_square, RIGHT, buff=0, aligned_edge=DOWN)

            squares.append(square)

            # 创建标签
            label = Text(str(fib[i])).scale(0.5).move_to(square.get_center())
            labels.append(label)

            # 更新整个数列值的文本
            fib_text.become(Text(f"斐波那契数列: {fib[:i + 1]}").scale(0.5).to_edge(UP))

            # 更新起始位置和方向
            if np.allclose(direction, RIGHT):
                direction = UP
            elif np.allclose(direction, UP):
                direction = LEFT
            elif np.allclose(direction, LEFT):
                direction = DOWN
            else:
                direction = RIGHT

            # 动画序列
            if i == 0:
                # 第一个正方形的创建动画，增加 run_time 到 1.5 秒
                self.play(Create(square), Write(label), FadeIn(fib_text), run_time=1.5)
            else:
                # 后续正方形的创建动画，增加 run_time 到 1 秒
                self.play(Create(square), Write(label), Transform(fib_text, Text(f"斐波那契数列: {fib[:i + 1]}").scale(0.5).to_edge(UP)), run_time=1)

        # 创建黄金螺旋线
        spiral = VMobject()

        # 定义角点方向顺序
        corner_directions = [DR, UR, UL, DL]
        corner_index = 0

        # 以第一个正方形的右下角为起点
        start_point = squares[0].get_corner(DR)
        spiral.start_new_path(start_point)

        start_angles = [0,PI/2,PI,3*PI/2,0,PI/2,PI,3*PI/2]
        for i in range(n):
            square = squares[i]
            # 获取当前正方形的角点
            corner = square.get_corner(corner_directions[corner_index % len(corner_directions)])
            # 直接使用当前正方形的边长作为圆弧半径
            radius = square.side_length
            # 计算圆心位置
            center = None
            current_corner = corner_directions[corner_index % len(corner_directions)]

            if np.allclose(current_corner, DR):
                # 角点在右下时，圆心在当前正方形的左下
                center = square.get_corner(DL)
            elif np.allclose(current_corner, UR):
                # 角点在右上时，圆心在当前正方形的右下
                center = square.get_corner(DR)
            elif np.allclose(current_corner, UL):
                # 角点在左上时，圆心在当前正方形的右上
                center = square.get_corner(UR)
            elif np.allclose(current_corner, DL):
                # 角点在左下时，圆心在当前正方形的左上
                center = square.get_corner(UL)
            
            # 创建圆弧，指定圆心位置
            arc = Arc(radius=radius, start_angle=start_angles[i], angle=PI / 2, arc_center=center)
            
            # 将圆弧添加到螺旋线中
            spiral.append_points(arc.points)
        
            # # 更新起始点
            start_point = corner
        
            # 更新角点索引
            corner_index += 1
        
        # 让螺线更加平滑
        spiral.make_smooth()
        
        # 设置螺线颜色为金色
        spiral.set_color(GOLD_A)
        spiral.set_stroke(width=6)
        
        # 螺旋线的创建动画，增加 run_time 到 2 秒
        self.play(Create(spiral), run_time=2)
        self.wait(2)